package com.kjlink.widget.monitoring.schedule.handle;

import com.kjlink.common.base.vo.BooleanWithMsg;
import com.kjlink.widget.monitoring.config.MonitorConfigParams;
import com.kjlink.widget.monitoring.entity.MonitorEventBatch;
import com.kjlink.widget.monitoring.entity.MonitorRawEvent;
import com.kjlink.widget.monitoring.helper.MonitorModelBuilderHelper;
import com.kjlink.widget.monitoring.repository.MonitorEventBatchRepository;
import com.kjlink.widget.monitoring.service.EventBatchService;
import com.kjlink.widget.monitoring.util.UDPUtil;
import com.kjlink.widget.monitoring.xml.AppRootXml;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 描述:
 * 处理批次上送 任务
 *
 * @author Vic.xu
 * @since 2025-08-08 17:30
 */
@Service
@Slf4j
public class MonitorEventSendHandler {

    private static LocalDateTime lastSendEndTime = null;

    @Resource
    private MonitorEventBatchRepository batchRepository;

    @Resource
    private EventBatchService eventBatchService;

    @Value("${monitor.udp.server.port:9876}")
    private int port;
    @Value("${monitor.udp.server.ip:}")
    private String ip;

    @Resource
    private MonitorModelBuilderHelper xmlReportBuilderHelper;

    @Resource
    private MonitorConfigParams monitorConfigParams;

    /**
     * 上送批次到第三方, 只处理 状态为 initial 的批次
     */
    public Map<Boolean, Integer> sendBatchesToThirdParty() {
        log.info("开始上送批次到第三方");
        Map<Boolean, Integer> result = new HashMap<>();
        result.put(true, 0);
        result.put(false, 0);
        // 查询所有待上送的批次   失败的 不管,  交给相同事件的下一个处罚时候处理
        LocalDateTime now = LocalDateTime.now();
        List<MonitorEventBatch> pendingBatches = batchRepository.findPendingBatches(
                MonitorEventBatch.BatchStatus.initial, lastSendEndTime);
        // 上次处理时间 :  但是减掉 窗口时间 * 2, 防止漏掉待上传的数据
        // 不再处理 上次处理时间, 只处理当前时间窗口内
        //Duration duration = Duration.ofMinutes(monitorConfigParams.getBatchWindowMinutes() * 2);
        //lastSendEndTime = MonitorCommonHelper.lastOperateTime(now, duration);

        if (pendingBatches.isEmpty()) {
            log.info("No pending batches to send");
            return result;
        }
        //开始发送 共n条
        log.info("开始逐条处理待上报事件源, 共{} 条", pendingBatches.size());
        for (MonitorEventBatch batch : pendingBatches) {
            boolean processResult = uploadBatch(batch);
            result.put(processResult, result.get(processResult) + 1);
        }
        log.info("处理完成");
        return result;
    }

    /**
     * 处理批次  上送到第三方
     */
    private boolean uploadBatch(MonitorEventBatch batch) {
        try {

            // 调用第三方接口
            BooleanWithMsg sendSuccess = this.send(batch);
            if (!sendSuccess.isSuccess()) {
                log.error("Failed to send batch {}: )", batch.getBatchNo(), sendSuccess.getMessage());
                updateBatchStatus(batch, MonitorEventBatch.BatchStatus.fail);
                return false;
            }
           updateBatchStatus(batch, MonitorEventBatch.BatchStatus.success);
            log.info("Sent batch {} to third party. Total events: {}",
                    batch.getBatchNo(), batch.getEventCount());
            return true;
        } catch (Exception e) {
            log.error("Exception occurred while sending batch {}", batch.getBatchNo(), e);
            updateBatchStatus(batch, MonitorEventBatch.BatchStatus.fail);
            return false;
        }
    }

    private void updateBatchStatus(MonitorEventBatch batch, MonitorEventBatch.BatchStatus status) {
        batch.setProcessTime(LocalDateTime.now());
        batch.setStatus(status);
        eventBatchService.saveInNewTransaction(batch);
    }


    /**
     * 上报监控事件数据
     *  会补齐 第一条 原始数据
     */
    public BooleanWithMsg send(MonitorEventBatch batch) {
        // 先把原始第一条时间补齐
        if (batch.getFirstRawEvent() == null) {
            MonitorRawEvent firstRawEvent = eventBatchService.findRawEventById(batch.getFirstEventId());
            batch.setFirstRawEvent(firstRawEvent);
            if (firstRawEvent == null) {
                log.error("No first raw event found for batch {}", batch.getBatchNo());
                return BooleanWithMsg.fail("No first raw event found for batch: " + batch.getBatchNo());
            }
        }
        Assert.notNull(batch, "上报批次对象不可为空");
        AppRootXml appRootXml = xmlReportBuilderHelper.buildXml(batch);
        return sentXml(appRootXml);
    }


    /**
     * 上报监控事件数据
     */
    public BooleanWithMsg sentXml(AppRootXml appRoot) {
        Assert.notNull(appRoot, "上报xml对象不可为空");
        try {
            String xml = appRoot.toXml();
            return UDPUtil.send(ip, port, xml);
        } catch (Exception e) {
            log.error("发送xml异常:{}", e.getMessage(), e);
            return BooleanWithMsg.fail("xml转换异常:" + e.getMessage());
        }
    }
}
